// TestZLib.cpp : Defines the entry point for the DLL.
// (C) 2016 Dacris Software Inc.
//

#include "stdafx.h"
#include <windows.h>
#include <malloc.h>
#include "zlib.h"
#include "BmarkPlugins.h"

#define TEST_TITLE_STR	"Compression"
#define TEST_UNIT_STR	"KB/s"
#define BUF_SIZE		393216
#define UPDATE_FREQ		250

extern "C" {
	char cDriveLetter;
	void* pTestBuf;
	BmarkApp* pBmarkApp;
	PluginData pluginData;
	PluginData progressData;
	BmarkNav navData;
	BmarkResult bmarkResult;

	HANDLE hThread;
	DWORD testThreadID;
	BOOL bThreadCancel;

	// returns number of bytes touched
	int CompressionTest()
	{
		DWORD dwBytesWritten = 0;
		DWORD dwBytesRead = 0;
		TCHAR lpszFileName[MAX_PATH];
		wsprintf(lpszFileName, "%c:\\Test.gz", cDriveLetter);
		gzFile gzf = gzopen(lpszFileName, "wb");
		dwBytesWritten = gzwrite(gzf, pTestBuf, BUF_SIZE);
		gzclose(gzf);
		gzf = gzopen(lpszFileName, "rb");
		dwBytesRead = gzread(gzf, pTestBuf, BUF_SIZE);
		gzclose(gzf);
		return (int)(dwBytesWritten + dwBytesRead);
	}

	void Cleanup()
	{
		TCHAR lpszFileName[MAX_PATH];
		wsprintf(lpszFileName, "%c:\\Test.gz", cDriveLetter);
		DeleteFile(lpszFileName);
	}

	DWORD WINAPI TestThread(LPVOID lpThreadParameter)
	{
		PluginData *app = (PluginData*)lpThreadParameter;
		DWORD startTicks = GetTickCount();
		DWORD currentTicks = startTicks;
		DWORD lastUpdate = 0;
		DWORD totalKB = 0;
		DWORD totalDuration = pBmarkApp->settings.iTestDuration
			* pBmarkApp->settings.iNumPasses
			* 1000;
		pBmarkApp->isTestRunning = TRUE;
		while (currentTicks - startTicks < totalDuration)
		{
			totalKB += CompressionTest()/1024;
			currentTicks = GetTickCount();

			if ((currentTicks - startTicks) / UPDATE_FREQ != lastUpdate)
			{
				if (bThreadCancel)
				{
					pBmarkApp->isTestRunning = FALSE;
					Cleanup();
					ExitThread(1);
					return 1;
				}
				lastUpdate = (currentTicks - startTicks) / UPDATE_FREQ;
				progressData.iValue = (100 * (currentTicks - startTicks)) / totalDuration;
				progressData.pValue = NULL;

				pluginData.iValue = BMARK_SET_PROGRESS;
				pluginData.pValue = &progressData;
				AppMessage(app, &pluginData);
			}
		}

		pBmarkApp->isTestRunning = FALSE;
		DWORD result = totalKB / ((currentTicks - startTicks) / 1000);

		pluginData.iValue = BMARK_HIDE_PROGRESS;
		pluginData.pValue = NULL;
		AppMessage(app, &pluginData);

		bmarkResult.result = result;

		pluginData.iValue = BMARK_SET_RESULT;
		pluginData.pValue = &bmarkResult;
		AppMessage(app, &pluginData);

		Cleanup();
		ExitThread(0);
		return 0;
	}

	void __declspec(dllexport) DllPluginFunction(int ordinal, PluginData *app)
	{
		if (ordinal == BMARK_ATTACH)
		{
			navData.cbTitle = lstrlen(TEST_TITLE_STR) + 1;
			navData.iOrdinal = 0;
			lstrcpy(navData.lpszTitle, TEST_TITLE_STR);

			pluginData.iValue = BMARK_REG_NAV;
			pluginData.pValue = &navData;
			
			AppMessage(app, &pluginData);

			lstrcpy(bmarkResult.unit, TEST_UNIT_STR);
			lstrcpy(bmarkResult.title, TEST_TITLE_STR);

			pluginData.iValue = BMARK_REG_RESULT;
			pluginData.pValue = &bmarkResult;

			AppMessage(app, &pluginData);
		}
		if (ordinal == BMARK_SETUP)
		{
			pBmarkApp = (BmarkApp*)(app->pValue);
			pTestBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BUF_SIZE);
			FillMemory(pTestBuf, BUF_SIZE, (BYTE)'*');
		}
		if (ordinal == BMARK_EXEC)
		{
			cDriveLetter = pBmarkApp->settings.cDriveLetter;
			if (cDriveLetter < 'A' || cDriveLetter > 'z' || 
				(cDriveLetter < 'a' && cDriveLetter > 'Z'))
			{
				pBmarkApp->isTestRunning = FALSE;
				MessageBox(NULL, "Invalid drive letter in hard disk test.", TEST_TITLE_STR, MB_OK|MB_ICONINFORMATION);
				return;
			}

			pluginData.iValue = BMARK_SHOW_PROGRESS;
			pluginData.pValue = NULL;
			AppMessage(app, &pluginData);

			bThreadCancel = FALSE;
			if (hThread)
			{
				CloseHandle(hThread);
			}
			hThread = CreateThread(NULL, 0, TestThread, app, 0, &testThreadID);
		}
		if (ordinal == BMARK_CANCEL_TEST)
		{
			bThreadCancel = TRUE;
		}
		if (ordinal == BMARK_EXIT)
		{
			pBmarkApp = (BmarkApp*)(app->pValue);
			HeapFree(GetProcessHeap(), 0, pTestBuf);
			if (hThread)
			{
				CloseHandle(hThread);
			}
		}
	}
};